// import com.alibaba.druid.DbType;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
// import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeIntervalDay;
// import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeIntervalYear;
// import com.alibaba.druid.sql.dialect.oracle.ast.clause.*;
// import com.alibaba.druid.sql.dialect.oracle.ast.clause.ModelClause.*;
// import com.alibaba.druid.sql.dialect.oracle.ast.expr.*;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.*;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterTableSplitPartition.NestedTablePartitionSpec;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterTableSplitPartition.TableSpaceItem;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterTableSplitPartition.UpdateIndexesClause;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement.ConditionalInsertClause;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement.OracleMultiInsertStatement_ConditionalInsertClauseItem_ptr;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement.InsertIntoClause;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectRestriction.CheckOption;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectRestriction.ReadOnly;
// import com.alibaba.druid.sql.dialect.oracle.parser.OracleFunctionDataType;
// import com.alibaba.druid.sql.dialect.oracle.parser.OracleProcedureDataType;
// import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;

// import java.util.List;

#include "OracleOutputVisitor.h"
#include <any>
#include "../../../../DbType.h"
#include "../../../ast/SQLHint.h"
#include "../../../ast/SQLExpr.h"
#include "../../../ast/SQLOver.h"
#include "../../../ast/SQLOrderBy.h"
#include "../../../ast/SQLUnpivot.h"
#include "../../../ast/SQLSetQuantifier.h"
#include "../../../ast/SQLArgument.h"
#include "../../../ast/SQLPartitionBy.h"
#include "../../../ast/SQLPartition.h"
#include "../../../ast/SQLParameter.h"
#include "../../../ast/SQLSubPartition.h"
#include "../../../ast/SQLPartitionValue.h"
#include "../../../ast/expr/SQLBetweenExpr.h"
#include "../../../ast/expr/SQLVariantRefExpr.h"
#include "../../../ast/statement/SQLCharacterDataType.h"
#include "../../../ast/statement/SQLWithSubqueryClause.h"
#include "../../../ast/statement/SQLJoinTableSource.h"
#include "../../../ast/statement/SQLTruncateStatement.h"
#include "../../../ast/statement/SQLSelectQueryBlock.h"
#include "../../../ast/statement/SQLAlterTableStatement.h"
#include "../../../ast/statement/SQLMergeStatement.h"
#include "../../../ast/statement/SQLUpdateSetItem.h"
#include "../../../ast/statement/SQLInsertStatement.h"
#include "../../../ast/statement/SQLErrorLoggingClause.h"
#include "../../../ast/statement/SQLAlterProcedureStatement.h"
#include "../../../ast/statement/SQLAlterTableRename.h"
#include "../../../ast/statement/SQLAlterTableItem.h"
#include "../../../ast/statement/SQLColumnDefinition.h"
#include "../../../ast/statement/SQLIfStatement.h"
#include "../../../ast/statement/SQLExternalRecordFormat.h"
#include "../../../ast/statement/SQLSavePointStatement.h"
#include "../../../ast/statement/SQLCreateFunctionStatement.h"
#include "../../../ast/statement/SQLBlockStatement.h"
#include "../../../ast/statement/SQLUnique.h"
#include "../../../ast/statement/SQLCheck.h"
#include "../ast/OracleDataTypeIntervalDay.h"
#include "../ast/OracleDataTypeIntervalYear.h"
#include "../ast/OracleSegmentAttributes.h"
#include "../ast/OracleSegmentAttributesImpl.h"
#include "../ast/stmt/OracleAlterTableRowMovement.h"
#include "../ast/stmt/OracleAlterTableSplitPartition.h"
#include "../ast/stmt/OracleMultiInsertStatement.h"
#include "../ast/stmt/OracleSelectRestriction.h"
#include "../ast/stmt/OracleDeleteStatement.h"
#include "../ast/stmt/OracleSelectJoin.h"
#include "../ast/stmt/OracleSelectQueryBlock.h"
#include "../ast/stmt/OracleSelectSubqueryTableSource.h"
#include "../ast/stmt/OracleExceptionStatement.h"
#include "../ast/stmt/OracleSelectTableReference.h"
#include "../ast/stmt/OracleUpdateStatement.h"
#include "../ast/stmt/OracleInsertStatement.h"
#include "../ast/stmt/OracleAlterSessionStatement.h"
#include "../ast/stmt/OracleSetTransactionStatement.h"
#include "../ast/stmt/OracleLockTableStatement.h"
#include "../ast/stmt/OracleExplainStatement.h"
#include "../ast/stmt/OracleAlterTableDropPartition.h"
#include "../ast/stmt/OracleAlterTableTruncatePartition.h"
#include "../ast/stmt/OracleUnique.h"
#include "../ast/stmt/OracleCreateTypeStatement.h"
#include "../ast/stmt/OracleAlterViewStatement.h"
#include "../ast/stmt/OracleAlterTableModify.h"
#include "../ast/stmt/OracleCreateIndexStatement.h"
#include "../ast/stmt/OracleCreateTableStatement.h"
#include "../ast/stmt/OracleRunStatement.h"
#include "../ast/stmt/OracleCheck.h"
#include "../ast/stmt/OracleConstraint.h"
#include "../ast/stmt/OraclePrimaryKey.h"
#include "../ast/stmt/OracleFileSpecification.h"
#include "../ast/stmt/OracleForStatement.h"
#include "../ast/stmt/OracleXmlColumnProperties.h"
#include "../ast/stmt/OracleDropDbLinkStatement.h"
#include "../ast/stmt/OracleUsingIndexClause.h"
#include "../ast/stmt/OracleSupplementalIdKey.h"
#include "../ast/stmt/OracleExitStatement.h"
#include "../ast/stmt/OracleGotoStatement.h"
#include "../ast/stmt/OracleLabelStatement.h"
#include "../ast/stmt/OracleAlterSynonymStatement.h"
#include "../ast/stmt/OracleContinueStatement.h"
#include "../ast/stmt/OracleCreateSynonymStatement.h"
#include "../ast/stmt/OracleAlterTriggerStatement.h"
#include "../ast/stmt/OracleAlterTableMoveTablespace.h"
#include "../ast/stmt/OracleAlterSummaryStatement.h"
#include "../ast/stmt/OracleAlterTablespaceStatement.h"
#include "../ast/stmt/OracleCreateDatabaseDbLinkStatement.h"
#include "../ast/stmt/OracleAlterTableShrinkSpace.h"
#include "../ast/stmt/OracleAlterTablespaceAddDataFile.h"
#include "../ast/stmt/OracleAlterTablespaceItem.h"
#include "../ast/stmt/OracleExecuteImmediateStatement.h"
#include "../ast/stmt/OracleCreatePackageStatement.h"
#include "../ast/stmt/OracleRaiseStatement.h"
#include "../ast/stmt/OracleForeignKey.h"
#include "../ast/stmt/OracleSupplementalLogGrp.h"
#include "../ast/stmt/OraclePipeRowStatement.h"
#include "../ast/expr/OracleAnalytic.h"
#include "../ast/expr/OracleTreatExpr.h"
#include "../ast/expr/OracleAnalyticWindowing.h"
#include "../ast/expr/OracleIntervalExpr.h"
#include "../ast/expr/OracleIntervalType.h"
#include "../ast/expr/OracleBinaryFloatExpr.h"
#include "../ast/expr/OracleBinaryDoubleExpr.h"
#include "../ast/expr/OracleOuterExpr.h"
#include "../ast/expr/OracleIsSetExpr.h"
#include "../ast/expr/OracleDatetimeExpr.h"
#include "../ast/expr/OracleSysdateExpr.h"
#include "../ast/expr/OracleArgumentExpr.h"
#include "../ast/expr/OracleRangeExpr.h"
#include "../ast/expr/OracleIsOfTypeExpr.h"
#include "../ast/clause/OracleReturningClause.h"
#include "../ast/clause/ModelClause.h"
#include "../ast/clause/PartitionExtensionClause.h"
#include "../ast/clause/SampleClause.h"
#include "../ast/clause/OracleWithSubqueryEntry.h"
#include "../ast/clause/SearchClause.h"
#include "../ast/clause/CycleClause.h"
#include "../ast/clause/OracleLobStorageClause.h"
#include "../ast/clause/OracleStorageClause.h"
#include "../parser/OracleFunctionDataType.h"
#include "../parser/OracleProcedureDataType.h"
#include "../../../../utils/instanceof.h"
#include "../../../../utils/listTran.h"
#include "../../../../utils/StringUtils.h"

OracleOutputVisitor::OracleOutputVisitor(std::stringstream *appender)
    : OracleOutputVisitor(appender, BOOL::TRUE)
{
}

OracleOutputVisitor::OracleOutputVisitor(std::stringstream *appender, BOOL_ptr printPostSemi)
    : SQLASTOutputVisitor(appender)
{
  this->dbType = DbType_ptr(new DbType(&DbType::oracle));
  this->printPostSemi = printPostSemi;
}

BOOL_ptr OracleOutputVisitor::isPrintPostSemi()
{
  return printPostSemi;
}

void OracleOutputVisitor::printHints(SQLHint_list_ptr hints)
{
  if (hints->size() > 0)
  {
    print0("/*+ ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLHint, SQLObject>(hints);
    printAndAccept(tmp1, make_string_ptr(", "));
    print0(" */");
  }
}

BOOL_ptr OracleOutputVisitor::visit(OracleAnalytic_ptr x)
{
  print0(ucase ? "(" : "(");

  BOOL_ptr space = BOOL::FALSE;
  if (x->getPartitionBy()->size() > 0)
  {
    print0(ucase ? "PARTITION BY " : "partition by ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getPartitionBy());
    printAndAccept(tmp1, make_string_ptr(", "));

    space = BOOL::TRUE;
  }

  SQLOrderBy_ptr orderBy = x->getOrderBy();
  if (orderBy != nullptr)
  {
    if (space)
    {
      print(' ');
    }
    SQLASTOutputVisitor::visit(orderBy);
    space = BOOL::TRUE;
  }

  OracleAnalyticWindowing_ptr windowing = x->getWindowing();
  if (windowing != nullptr)
  {
    if (space)
    {
      print(' ');
    }
    visit(windowing);
  }

  if (x->isWindowingPreceding())
  {
    print0(ucase ? " PRECEDING" : " preceding");
  }

  print(')');

  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleAnalyticWindowing_ptr x)
{
  print0(StringUtils::toUpper(x->getType()->name));
  print(' ');

  SQLExpr_ptr expr = x->getExpr();

  if (instanceof <SQLExpr, SQLBetweenExpr>(expr) &&
      instanceof <SQLObject, SQLOver>(x->getParent()))
  {
    SQLOver_ptr over = std::dynamic_pointer_cast<SQLOver>(x->getParent());
    SQLBetweenExpr_ptr betweenExpr = std::dynamic_pointer_cast<SQLBetweenExpr>(expr);
    SQLOver_WindowingBound_ptr beginBound = over->getWindowingBetweenBeginBound();
    if (beginBound != nullptr)
    {
      print0(ucase ? " BETWEEN " : " between ");
      betweenExpr->getBeginExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
      print(' ');
      print0(ucase ? beginBound->name : beginBound->nameLCase);
      print0(ucase ? " AND " : " and ");
      betweenExpr->getEndExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
      return BOOL::FALSE;
    }
  }

  expr->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleDeleteStatement_ptr x)
{
  print0(ucase ? "DELETE " : "delete ");

  SQLTableSource_ptr tableSource = x->getTableSource();
  if (x->getHints()->size() > 0)
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLHint, SQLObject>(x->getHints());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(' ');
  }

  print0(ucase ? "FROM " : "from ");
  if (x->isOnly())
  {
    print0(ucase ? "ONLY (" : "only (");
    x->getTableName()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');

    printAlias(x->getAlias());
  }
  else
  {
    x->getTableSource()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getWhere() != nullptr)
  {
    println();
    this->indentCount++;
    print0(ucase ? "WHERE " : "where ");
    x->getWhere()->accept(std::make_shared<OracleOutputVisitor>(*this));
    this->indentCount--;
  }

  if (x->getReturning() != nullptr)
  {
    println();
    x->getReturning()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleIntervalExpr_ptr x)
{
  SQLExpr_ptr value = x->getValue();
  if (instanceof <SQLExpr, SQLLiteralExpr>(value) ||
      instanceof <SQLExpr, SQLVariantRefExpr>(value))
  {
    print0(ucase ? "INTERVAL " : "interval ");
    value->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(' ');
  }
  else
  {
    print('(');
    value->accept(std::make_shared<OracleOutputVisitor>(*this));
    print0(") ");
  }

  print0(x->getType()->name);

  if (x->getPrecision() != nullptr)
  {
    print('(');
    printExpr(x->getPrecision(), parameterized);
    // if (x->getFactionalSecondsPrecision() != nullptr) {
    print0(", ");
    print(x->getFactionalSecondsPrecision());
    // }
    print(')');
  }

  if (x->getToType() != nullptr)
  {
    print0(ucase ? " TO " : " to ");
    print0(x->getToType()->name);
    if (x->getToFactionalSecondsPrecision() != nullptr)
    {
      print('(');
      printExpr(x->getToFactionalSecondsPrecision(), parameterized);
      print(')');
    }
  }

  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleOuterExpr_ptr x)
{
  x->getExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0("(+)");
  return BOOL::FALSE;
}

bool OracleOutputVisitor::visit(SQLScriptCommitStatement_ptr astNode)
{
  print('/');
  println();
  return false;
}

bool OracleOutputVisitor::visit(SQLSelect_ptr x)
{
  SQLWithSubqueryClause_ptr with = x->getWithSubQuery();
  if (with != nullptr)
  {
    with->accept(std::make_shared<OracleOutputVisitor>(*this));
    println();
  }

  SQLSelectQuery_ptr query = x->getQuery();
  query->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->getRestriction() != nullptr)
  {
    println();
    print("WITH ");
    x->getRestriction()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLOrderBy_ptr orderBy = x->getOrderBy();
  if (orderBy != nullptr)
  {
    bool hasFirst = false;
    if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(query))
    {
      SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(query);
      if (queryBlock->getFirst() != nullptr)
      {
        hasFirst = true;
      }
      else
      {
        hasFirst = false;
      }
    }

    if (hasFirst != true)
    {
      println();
      orderBy->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  return false;
}

BOOL_ptr OracleOutputVisitor::visit(OracleSelectJoin_ptr x)
{
  x->getLeft()->accept(std::make_shared<OracleOutputVisitor>(*this));
  SQLTableSource_ptr right = x->getRight();

  if (x->getJoinType()->name->c_str() == SQLJoinTableSource_JoinType::COMMA.name->c_str())
  {
    print0(", ");
    x->getRight()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  else
  {
    bool isRoot = instanceof <SQLObject, SQLSelectQueryBlock>(x->getParent());
    if (isRoot)
    {
      this->indentCount++;
    }

    println();
    print0(ucase ? x->getJoinType()->name : x->getJoinType()->nameLCase);
    print(' ');

    if (instanceof <SQLTableSource, SQLJoinTableSource>(right))
    {
      print('(');
      incrementIndent();
      println();
      right->accept(std::make_shared<OracleOutputVisitor>(*this));
      decrementIndent();
      println();
      print(')');
    }
    else
    {
      right->accept(std::make_shared<OracleOutputVisitor>(*this));
    }

    if (isRoot)
    {
      this->indentCount--;
    }

    if (x->getCondition() != nullptr)
    {
      print0(ucase ? " ON " : " on ");
      incrementIndent();
      x->getCondition()->accept(std::make_shared<OracleOutputVisitor>(*this));
      decrementIndent();
      print(' ');
    }

    if (x->getUsing()->size() > 0)
    {
      print0(ucase ? " USING (" : " using (");
      SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getUsing());
      printAndAccept(tmp1, make_string_ptr(", "));
      print(')');
    }

    printFlashback(x->getFlashback());
  }

  SQLPivot_ptr pivot = x->getPivot();
  if (pivot != nullptr)
  {
    println();
    pivot->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLUnpivot_ptr unpivot = x->getUnpivot();
  if (unpivot != nullptr)
  {
    println();
    unpivot->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  return BOOL::FALSE;
}

bool OracleOutputVisitor::visit(SQLSelectOrderByItem_ptr x)
{
  x->getExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
  if (x->getType() != nullptr)
  {
    print(' ');

    string_ptr typeName = x->getType()->name;
    print0(ucase ? StringUtils::toUpper(typeName) : StringUtils::toLower(typeName));
  }

  if (x->getNullsOrderType() != nullptr)
  {
    print(' ');
    print0(x->getNullsOrderType()->toFormalString());
  }

  return false;
}

bool OracleOutputVisitor::visit(SQLSelectQueryBlock_ptr select)
{
  if (instanceof <SQLSelectQueryBlock, OracleSelectQueryBlock>(select))
  {
    return visit(std::dynamic_pointer_cast<OracleSelectQueryBlock>(select));
  }

  return SQLASTOutputVisitor::visit(select);
}

bool OracleOutputVisitor::visit(OracleSelectQueryBlock_ptr x)
{
  if (isPrettyFormat() && x->hasBeforeComment())
  {
    printlnComments(x->getBeforeCommentsDirect());
  }

  print0(ucase ? "SELECT " : "select ");

  if (x->getHintsSize() > 0)
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLCommentHint, SQLObject>(x->getHints());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(' ');
  }

  if (SQLSetQuantifier::ALL == x->getDistionOption())
  {
    print0(ucase ? "ALL " : "all ");
  }
  else if (SQLSetQuantifier::DISTINCT == x->getDistionOption())
  {
    print0(ucase ? "DISTINCT " : "distinct ");
  }
  else if (SQLSetQuantifier::UNIQUE == x->getDistionOption())
  {
    print0(ucase ? "UNIQUE " : "unique ");
  }

  printSelectList(x->getSelectList());

  if (x->getInto() != nullptr)
  {
    println();
    print0(ucase ? "INTO " : "into ");
    x->getInto()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  println();
  print0(ucase ? "FROM " : "from ");
  if (x->getFrom() == nullptr)
  {
    print0(ucase ? "DUAL" : "dual");
  }
  else
  {
    x->getFrom()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getWhere() != nullptr)
  {
    printWhere(x->getWhere());
  }

  printHierarchical(x);

  if (x->getGroupBy() != nullptr)
  {
    println();
    x->getGroupBy()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getModelClause() != nullptr)
  {
    println();
    x->getModelClause()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLOrderBy_ptr orderBy = x->getOrderBy();
  if (orderBy != nullptr)
  {
    println();
    orderBy->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  printFetchFirst(x);

  if (x->isForUpdate())
  {
    println();
    print0(ucase ? "FOR UPDATE" : "for update");
    if (x->getForUpdateOfSize() > 0)
    {
      print('(');
      SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getForUpdateOf());
      printAndAccept(tmp1, make_string_ptr(", "));
      print(')');
    }

    if (x->isNoWait())
    {
      print0(ucase ? " NOWAIT" : " nowait");
    }
    else if (x->isSkipLocked())
    {
      print0(ucase ? " SKIP LOCKED" : " skip locked");
    }
    else if (x->getWaitTime() != nullptr)
    {
      print0(ucase ? " WAIT " : " wait ");
      x->getWaitTime()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  return false;
}

BOOL_ptr OracleOutputVisitor::visit(OracleSelectRestriction_CheckOption_ptr x)
{
  print0(ucase ? "CHECK OPTION" : "check option");
  if (x->getConstraint() != nullptr)
  {
    print0(ucase ? " CONSTRAINT" : " constraint");
    print(' ');
    x->getConstraint()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleSelectRestriction_ReadOnly_ptr x)
{
  print0(ucase ? "READ ONLY" : "read only");
  if (x->getConstraint() != nullptr)
  {
    print0(ucase ? " CONSTRAINT" : " constraint");
    print(' ');
    x->getConstraint()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleSelectSubqueryTableSource_ptr x)
{
  print('(');
  this->indentCount++;
  println();
  x->getSelect()->accept(std::make_shared<OracleOutputVisitor>(*this));
  this->indentCount--;
  println();
  print(')');

  SQLPivot_ptr pivot = x->getPivot();
  if (pivot != nullptr)
  {
    println();
    pivot->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLUnpivot_ptr unpivot = x->getUnpivot();
  if (unpivot != nullptr)
  {
    println();
    unpivot->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  printFlashback(x->getFlashback());

  if ((x->getAlias() != nullptr) && (x->getAlias()->length() != 0))
  {
    print(' ');
    print0(x->getAlias());
  }

  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleSelectTableReference_ptr x)
{
  if (x->isOnly())
  {
    print0(ucase ? "ONLY (" : "only (");
    printTableSourceExpr(x->getExpr());

    if (x->getPartition() != nullptr)
    {
      print(' ');
      x->getPartition()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }

    print(')');
  }
  else
  {
    printTableSourceExpr(x->getExpr());

    if (x->getPartition() != nullptr)
    {
      print(' ');
      x->getPartition()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  if (x->getHints()->size() > 0)
  {
    this->printHints(x->getHints());
  }

  if (x->getSampleClause() != nullptr)
  {
    print(' ');
    x->getSampleClause()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getPivot() != nullptr)
  {
    println();
    x->getPivot()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLUnpivot_ptr unpivot = x->getUnpivot();
  if (unpivot != nullptr)
  {
    println();
    unpivot->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  printFlashback(x->getFlashback());

  printAlias(x->getAlias());

  return BOOL::FALSE;
}

void OracleOutputVisitor::printFlashback(SQLExpr_ptr flashback)
{
  if (flashback == nullptr)
  {
    return;
  }

  println();

  if (instanceof <SQLExpr, SQLBetweenExpr>(flashback))
  {
    flashback->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  else
  {
    print0(ucase ? "AS OF " : "as of ");
    flashback->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
}

BOOL_ptr OracleOutputVisitor::visit(OracleUpdateStatement_ptr x)
{
  print0(ucase ? "UPDATE " : "update ");

  if (x->getHints()->size() > 0)
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLHint, SQLObject>(x->getHints());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(' ');
  }

  if (x->isOnly())
  {
    print0(ucase ? "ONLY (" : "only (");
    x->getTableSource()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');
  }
  else
  {
    x->getTableSource()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  printAlias(x->getAlias());

  println();

  print0(ucase ? "SET " : "set ");
  auto it_getItems = x->getItems()->begin();
  for (int i = 0, size = x->getItems()->size(); i < size; ++i)
  {
    if (i != 0)
    {
      print0(", ");
    }
    std::advance(it_getItems, i);
    (*it_getItems)->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getWhere() != nullptr)
  {
    println();
    print0(ucase ? "WHERE " : "where ");
    this->indentCount++;
    x->getWhere()->accept(std::make_shared<OracleOutputVisitor>(*this));
    this->indentCount--;
  }

  if (x->getReturning()->size() > 0)
  {
    println();
    print0(ucase ? "RETURNING " : "returning ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getReturning());
    printAndAccept(tmp1, make_string_ptr(", "));
    print0(ucase ? " INTO " : " into ");
    SQLObject_list_ptr tmp2 = ListTran::tran_class<SQLExpr, SQLObject>(x->getReturningInto());
    printAndAccept(tmp2, make_string_ptr(", "));
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(SampleClause_ptr x)
{
  print0(ucase ? "SAMPLE " : "sample ");

  if (x->isBlock())
  {
    print0(ucase ? "BLOCK " : "block ");
  }

  print('(');
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getPercent());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');

  if (x->getSeedValue() != nullptr)
  {
    print0(ucase ? " SEED (" : " seed (");
    x->getSeedValue()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(PartitionExtensionClause_ptr x)
{
  if (x->isSubPartition())
  {
    print0(ucase ? "SUBPARTITION " : "subpartition ");
  }
  else
  {
    print0(ucase ? "PARTITION " : "partition ");
  }

  if (x->getPartition() != nullptr)
  {
    print('(');
    x->getPartition()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');
  }
  else
  {
    print0(ucase ? "FOR (" : "for (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(x->getFor());
    printAndAccept(tmp1, make_string_ptr(","));
    print(')');
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleWithSubqueryEntry_ptr x)
{
  print0(x->getAlias());

  if (x->getColumns()->size() > 0)
  {
    print0(" (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(x->getColumns());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(')');
  }

  print0(ucase ? " AS " : " as ");
  print('(');
  this->indentCount++;
  println();
  x->getSubQuery()->accept(std::make_shared<OracleOutputVisitor>(*this));
  this->indentCount--;
  println();
  print(')');

  if (x->getSearchClause() != nullptr)
  {
    println();
    x->getSearchClause()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getCycleClause() != nullptr)
  {
    println();
    x->getCycleClause()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(SearchClause_ptr x)
{
  print0(ucase ? "SEARCH " : "search ");
  print0(x->getType()->name);
  print0(ucase ? " FIRST BY " : " first by ");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLSelectOrderByItem, SQLObject>(x->getItems());
  printAndAccept(tmp1, make_string_ptr(", "));
  print0(ucase ? " SET " : " set ");
  x->getOrderingColumn()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(CycleClause_ptr x)
{
  print0(ucase ? "CYCLE " : "cycle ");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getAliases());
  printAndAccept(tmp1, make_string_ptr(", "));
  print0(ucase ? " SET " : " set ");
  x->getMark()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " TO " : " to ");
  x->getValue()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " DEFAULT " : " default ");
  x->getDefaultValue()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleBinaryFloatExpr_ptr x)
{
  if (x != nullptr /*&& x->getValue() != nullptr*/)
  {
    SQLASTOutputVisitor::print0(std::to_string(x->getValue()));
    print('F');
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleBinaryDoubleExpr_ptr x)
{
  if (x != nullptr /*&& x->getValue() != nullptr*/)
  {
    SQLASTOutputVisitor::print0(std::to_string(x->getValue()));
    print('D');
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleIsSetExpr_ptr x)
{
  x->getNestedTable()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " IS A SET" : " is a set");
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_ReturnRowsClause_ptr x)
{
  if (x->isAll())
  {
    print0(ucase ? "RETURN ALL ROWS" : "return all rows");
  }
  else
  {
    print0(ucase ? "RETURN UPDATED ROWS" : "return updated rows");
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_ptr x)
{
  print0(ucase ? "MODEL" : "model");

  this->indentCount++;
  for (ModelClause_CellReferenceOption_ptr opt : *(x->getCellReferenceOptions()))
  {
    print(' ');
    print0(opt->name);
  }

  if (x->getReturnRowsClause() != nullptr)
  {
    print(' ');
    x->getReturnRowsClause()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  for (ModelClause_ReferenceModelClause_ptr item : *(x->getReferenceModelClauses()))
  {
    print(' ');
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  x->getMainModel()->accept(std::make_shared<OracleOutputVisitor>(*this));
  this->indentCount--;

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_MainModelClause_ptr x)
{
  if (x->getMainModelName() != nullptr)
  {
    print0(ucase ? " MAIN " : " main ");
    x->getMainModelName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  println();
  x->getModelColumnClause()->accept(std::make_shared<OracleOutputVisitor>(*this));

  for (ModelClause_CellReferenceOption_ptr opt : *(x->getCellReferenceOptions()))
  {
    println();
    print0(opt->name);
  }

  println();
  x->getModelRulesClause()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_ModelColumnClause_ptr x)
{
  if (x->getQueryPartitionClause() != nullptr)
  {
    x->getQueryPartitionClause()->accept(std::make_shared<OracleOutputVisitor>(*this));
    println();
  }

  print0(ucase ? "DIMENSION BY (" : "dimension by (");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<ModelClause_ModelColumn, SQLObject>(x->getDimensionByColumns());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');

  println();
  print0(ucase ? "MEASURES (" : "measures (");
  SQLObject_list_ptr tmp2 = ListTran::tran_class<ModelClause_ModelColumn, SQLObject>(x->getMeasuresColumns());
  printAndAccept(tmp2, make_string_ptr(", "));
  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_QueryPartitionClause_ptr x)
{
  print0(ucase ? "PARTITION BY (" : "partition by (");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getExprList());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_ModelColumn_ptr x)
{
  x->getExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
  if (x->getAlias() != nullptr)
  {
    print(' ');
    print0(x->getAlias());
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_ModelRulesClause_ptr x)
{
  if (x->getOptions()->size() > 0)
  {
    print0(ucase ? "RULES" : "rules");
    for (ModelClause_ModelRuleOption_ptr opt : *(x->getOptions()))
    {
      print(' ');
      print0(opt->name);
    }
  }

  if (x->getIterate() != nullptr)
  {
    print0(ucase ? " ITERATE (" : " iterate (");
    x->getIterate()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');

    if (x->getUntil() != nullptr)
    {
      print0(ucase ? " UNTIL (" : " until (");
      x->getUntil()->accept(std::make_shared<OracleOutputVisitor>(*this));
      print(')');
    }
  }

  print0(" (");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<ModelClause_CellAssignmentItem, SQLObject>(x->getCellAssignmentItems());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_CellAssignmentItem_ptr x)
{
  if (x->getOption() != nullptr)
  {
    print0(x->getOption()->name);
    print(' ');
  }

  x->getCellAssignment()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->getOrderBy() != nullptr)
  {
    print(' ');
    x->getOrderBy()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  print0(" = ");
  x->getExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(ModelClause_CellAssignment_ptr x)
{
  x->getMeasureColumn()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0("[");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getConditions());
  printAndAccept(tmp1, make_string_ptr(", "));
  print0("]");
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleReturningClause_ptr x)
{
  print0(ucase ? "RETURNING " : "returning ");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getItems());
  printAndAccept(tmp1, make_string_ptr(", "));
  print0(ucase ? " INTO " : " into ");
  SQLObject_list_ptr tmp2 = ListTran::tran_class<SQLExpr, SQLObject>(x->getValues());
  printAndAccept(tmp2, make_string_ptr(", "));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleInsertStatement_ptr x)
{
  // visit((SQLInsertStatement) x);

  print0(ucase ? "INSERT " : "insert ");

  if (x->getHints()->size() > 0)
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLHint, SQLObject>(x->getHints());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(' ');
  }

  print0(ucase ? "INTO " : "into ");

  x->getTableSource()->accept(std::make_shared<OracleOutputVisitor>(*this));

  printInsertColumns(x->getColumns());

  if (x->getValues() != nullptr)
  {
    println();
    print0(ucase ? "VALUES " : "values ");
    x->getValues()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  else
  {
    if (x->getQuery() != nullptr)
    {
      println();
      x->getQuery()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  if (x->getReturning() != nullptr)
  {
    println();
    x->getReturning()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getErrorLogging() != nullptr)
  {
    println();
    x->getErrorLogging()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleMultiInsertStatement_InsertIntoClause_ptr x)
{
  print0(ucase ? "INTO " : "into ");

  x->getTableSource()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->getColumns()->size() > 0)
  {
    this->indentCount++;
    println();
    print('(');
    auto it_getColumns = x->getColumns()->begin();
    for (int i = 0, size = x->getColumns()->size(); i < size; ++i)
    {
      if (i != 0)
      {
        if (i % 5 == 0)
        {
          println();
        }
        print0(", ");
      }
      std::advance(it_getColumns, i);
      (*it_getColumns)->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
    print(')');
    this->indentCount--;
  }

  if (x->getValues() != nullptr)
  {
    println();
    print0(ucase ? "VALUES " : "values ");
    x->getValues()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  else
  {
    if (x->getQuery() != nullptr)
    {
      println();
      x->getQuery()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleMultiInsertStatement_ptr x)
{
  print0(ucase ? "INSERT " : "insert ");

  if (x->getHints()->size() > 0)
  {
    this->printHints(x->getHints());
  }

  if (x->getOption() != nullptr)
  {
    print0(x->getOption()->name);
    print(' ');
  }

  auto it_getEntries = x->getEntries()->begin();
  for (int i = 0, size = x->getEntries()->size(); i < size; ++i)
  {
    this->indentCount++;
    println();
    std::advance(it_getEntries, i);
    (*it_getEntries)->accept(std::make_shared<OracleOutputVisitor>(*this));
    this->indentCount--;
  }

  println();
  x->getSubQuery()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleMultiInsertStatement_ConditionalInsertClause_ptr x)
{
  auto it_getItems = x->getItems()->begin();
  for (int i = 0, size = x->getItems()->size(); i < size; ++i)
  {
    if (i != 0)
    {
      println();
    }
    std::advance(it_getItems, i);
    OracleMultiInsertStatement_ConditionalInsertClauseItem_ptr item = *it_getItems;

    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getElseItem() != nullptr)
  {
    println();
    print0(ucase ? "ELSE" : "else");
    this->indentCount++;
    println();
    x->getElseItem()->accept(std::make_shared<OracleOutputVisitor>(*this));
    this->indentCount--;
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleMultiInsertStatement_ConditionalInsertClauseItem_ptr x)
{
  print0(ucase ? "WHEN " : "when ");
  x->getWhen()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " THEN" : " then");
  this->indentCount++;
  println();
  x->getThen()->accept(std::make_shared<OracleOutputVisitor>(*this));
  this->indentCount--;
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleLockTableStatement_ptr x)
{
  print0(ucase ? "LOCK TABLE " : "lock table ");
  x->getTable()->accept(std::make_shared<OracleOutputVisitor>(*this));
  if (x->getPartition() != nullptr)
  {
    print0(" PARTITION (");
    x->getPartition()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print0(") ");
  }
  print0(ucase ? " IN " : " in ");
  print0(x->getLockMode()->toString());
  print0(ucase ? " MODE " : " mode ");
  if (x->isNoWait())
  {
    print0(ucase ? "NOWAIT" : "nowait");
  }
  else if (x->getWait() != nullptr)
  {
    print0(ucase ? "WAIT " : "wait ");
    x->getWait()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterSessionStatement_ptr x)
{
  print0(ucase ? "ALTER SESSION SET " : "alter session set ");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLAssignItem, SQLObject>(x->getItems());
  printAndAccept(tmp1, make_string_ptr(", "));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleDatetimeExpr_ptr x)
{
  x->getExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
  SQLExpr_ptr timeZone = x->getTimeZone();

  if (instanceof <SQLExpr, SQLIdentifierExpr>(timeZone))
  {
    if (StringUtils::equalsIgnoreCase((std::dynamic_pointer_cast<SQLIdentifierExpr>(timeZone))->getName(), make_string_ptr("LOCAL")))
    {
      print0(ucase ? " AT LOCAL" : "alter session set ");
      return BOOL::FALSE;
    }
  }

  print0(ucase ? " AT TIME ZONE " : " at time zone ");
  timeZone->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleSysdateExpr_ptr x)
{
  print0(ucase ? "SYSDATE" : "sysdate");
  if (x->getOption() != nullptr)
  {
    print('@');
    print0(x->getOption());
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleExceptionStatement_Item_ptr x)
{
  print0(ucase ? "WHEN " : "when ");
  x->getWhen()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " THEN" : " then");

  this->indentCount++;
  auto it_getStatements = x->getStatements()->begin();
  if (x->getStatements()->size() > 1)
  {
    println();
  }
  else
  {
    if (x->getStatements()->size() == 1 && instanceof <SQLStatement, SQLIfStatement>(*it_getStatements))
    {
      println();
    }
    else
    {
      print(' ');
    }
  }

  for (int i = 0, size = x->getStatements()->size(); i < size; ++i)
  {
    if (i != 0 && size > 1)
    {
      println();
    }
    std::advance(it_getStatements, i);
    SQLStatement_ptr stmt = *it_getStatements;
    stmt->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  this->indentCount--;
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleExceptionStatement_ptr x)
{
  print0(ucase ? "EXCEPTION" : "exception");
  this->indentCount++;
  OracleExceptionStatement_Item_list_ptr items = x->getItems();
  auto it_items = items->begin();
  for (int i = 0, size = items->size(); i < size; ++i)
  {
    println();
    std::advance(it_items, i);
    OracleExceptionStatement_Item_ptr item = *it_items;
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  this->indentCount--;
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleArgumentExpr_ptr x)
{
  print0(x->getArgumentName());
  print0(" => ");
  x->getValue()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleSetTransactionStatement_ptr x)
{
  if (x->isReadOnly())
  {
    print0(ucase ? "SET TRANSACTION READ ONLY" : "set transaction read only");
  }
  else
  {
    print0(ucase ? "SET TRANSACTION" : "set transaction");
  }

  SQLExpr_ptr name = x->getName();
  if (name != nullptr)
  {
    print0(ucase ? " NAME " : " name ");
    name->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleExplainStatement_ptr x)
{
  print0(ucase ? "EXPLAIN PLAN" : "explain plan");
  this->indentCount++;
  println();
  if (x->getStatementId() != nullptr)
  {
    print0(ucase ? "SET STATEMENT_ID = " : "set statement_id = ");
    x->getStatementId()->accept(std::make_shared<OracleOutputVisitor>(*this));
    println();
  }

  if (x->getInto() != nullptr)
  {
    print0(ucase ? "INTO " : "into ");
    x->getInto()->accept(std::make_shared<OracleOutputVisitor>(*this));
    println();
  }

  print0(ucase ? "FOR" : "for");
  println();
  x->getStatement()->accept(std::make_shared<OracleOutputVisitor>(*this));

  this->indentCount--;
  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLAlterProcedureStatement_ptr x)
{
  print0(ucase ? "ALTER PROCEDURE " : "alter procedure ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  if (x->isCompile())
  {
    print0(ucase ? " COMPILE" : " compile");
  }
  if (x->isReuseSettings())
  {
    print0(ucase ? " REUSE SETTINGS" : " reuse settings");
  }
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableDropPartition_ptr x)
{
  print0(ucase ? "DROP PARTITION " : "drop partition ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLAlterTableStatement_ptr x)
{
  if (x->getItems()->size() == 1)
  {
    auto it_getItems = x->getItems()->begin();
    SQLAlterTableItem_ptr item = *it_getItems;
    if (instanceof <SQLAlterTableItem, SQLAlterTableRename>(item))
    {
      SQLExpr_ptr to = (std::dynamic_pointer_cast<SQLAlterTableRename>(item))->getTo()->getExpr();

      print0(ucase ? "RENAME " : "rename ");
      x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
      print0(ucase ? " TO " : " to ");
      to->accept(std::make_shared<OracleOutputVisitor>(*this));
      return false;
    }
  }

  print0(ucase ? "ALTER TABLE " : "alter table ");
  printTableSourceExpr(x->getName());
  this->indentCount++;
  for (SQLAlterTableItem_ptr item : *x->getItems())
  {
    println();
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  if (x->isUpdateGlobalIndexes())
  {
    println();
    print0(ucase ? "UPDATE GLOABL INDEXES" : "update gloabl indexes");
  }
  this->indentCount--;
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableTruncatePartition_ptr x)
{
  print0(ucase ? "TRUNCATE PARTITION " : "truncate partition ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableSplitPartition_TableSpaceItem_ptr x)
{
  print0(ucase ? "TABLESPACE " : "tablespace ");
  x->getTablespace()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableSplitPartition_UpdateIndexesClause_ptr x)
{
  print0(ucase ? "UPDATE INDEXES" : "update indexes");
  if (x->getItems()->size() > 0)
  {
    print('(');
    printAndAccept(x->getItems(), make_string_ptr(", "));
    print(')');
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableSplitPartition_ptr x)
{
  print0(ucase ? "SPLIT PARTITION " : "split partition ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->getAt()->size() > 0)
  {
    this->indentCount++;
    println();
    print0(ucase ? "AT (" : "at (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getAt());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(')');
    this->indentCount--;
  }

  if (x->getInto()->size() > 0)
  {
    println();
    this->indentCount++;
    print0(ucase ? "INTO (" : "into (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<OracleAlterTableSplitPartition_NestedTablePartitionSpec, SQLObject>(x->getInto());
    printAndAccept(tmp1, make_string_ptr(", "));
    print(')');
    this->indentCount--;
  }

  if (x->getUpdateIndexes() != nullptr)
  {
    println();
    this->indentCount++;
    x->getUpdateIndexes()->accept(std::make_shared<OracleOutputVisitor>(*this));
    this->indentCount--;
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableSplitPartition_NestedTablePartitionSpec_ptr x)
{
  print0(ucase ? "PARTITION " : "partition ");
  x->getPartition()->accept(std::make_shared<OracleOutputVisitor>(*this));
  for (SQLObject_ptr item : *x->getSegmentAttributeItems())
  {
    print(' ');
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableModify_ptr x)
{
  print0(ucase ? "MODIFY (" : "modify (");
  this->indentCount++;
  auto it_getColumns = x->getColumns()->begin();
  for (int i = 0, size = x->getColumns()->size(); i < size; ++i)
  {
    println();
    std::advance(it_getColumns, i);
    SQLColumnDefinition_ptr column = *it_getColumns;
    column->accept(std::make_shared<OracleOutputVisitor>(*this));
    if (i != size - 1)
    {
      print0(", ");
    }
  }
  this->indentCount--;
  println();
  print(')');

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCreateIndexStatement_ptr x)
{
  print0(ucase ? "CREATE " : "create ");
  if (x->getType() != nullptr)
  {
    print0(x->getType());
    print(' ');
  }

  print0(ucase ? "INDEX " : "index ");

  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " ON " : " on ");

  if (x->isCluster())
  {
    print0(ucase ? "CLUSTER " : "cluster ");
  }

  x->getTable()->accept(std::make_shared<OracleOutputVisitor>(*this));

  SQLSelectOrderByItem_list_ptr items = x->getItems();
  if (items->size() > 0)
  {
    print('(');
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLSelectOrderByItem, SQLObject>(items);
    printAndAccept(tmp1, make_string_ptr(", "));
    print(')');
  }

  if (x->isIndexOnlyTopLevel())
  {
    println();
    print0(ucase ? "INDEX ONLY TOPLEVEL" : "index only toplevel");
  }

  if (x->isComputeStatistics())
  {
    println();
    print0(ucase ? "COMPUTE STATISTICS" : "compute statistics");
  }

  if (x->isReverse())
  {
    println();
    print0(ucase ? "REVERSE" : "reverse");
  }

  this->printOracleSegmentAttributes(x);

  if (x->isOnline())
  {
    print0(ucase ? " ONLINE" : " online");
  }

  if (x->isNoParallel())
  {
    print0(ucase ? " NOPARALLEL" : " noparallel");
  }
  else if (x->getParallel() != nullptr)
  {
    print0(ucase ? " PARALLEL " : " parallel ");
    x->getParallel()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  BOOL_ptr sort = x->getSort();
  // if (sort != nullptr) {
  if (sort)
  {
    print0(ucase ? " SORT" : " sort");
  }
  else
  {
    print0(ucase ? " NOSORT" : " nosort");
  }
  // }

  if (x->getLocalPartitions()->size() > 0)
  {
    println();
    print0(ucase ? "LOCAL (" : "local (");
    this->indentCount++;
    println();
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLPartition, SQLObject>(x->getLocalPartitions());
    printlnAndAccept(tmp1, make_string_ptr(","));
    this->indentCount--;
    println();
    print(')');
  }
  else if (x->isLocal())
  {
    print0(ucase ? " LOCAL" : " local");
  }

  SQLName_list_ptr localStoreIn = x->getLocalStoreIn();
  if (localStoreIn->size() > 0)
  {
    print0(ucase ? " STORE IN (" : " store in (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(localStoreIn);
    printAndAccept(tmp1, make_string_ptr(", "));
    print(')');
  }

  SQLPartitionBy_list_ptr globalPartitions = x->getGlobalPartitions();
  if (globalPartitions->size() > 0)
  {
    for (auto globalPartition : *globalPartitions)
    {
      println();
      print0(ucase ? "GLOBAL " : "global ");
      print0(ucase ? "PARTITION BY " : "partition by ");
      (globalPartition)->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }
  else
  {
    if (x->isGlobal())
    {
      print0(ucase ? " GLOBAL" : " global");
    }
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleForStatement_ptr x)
{
  BOOL_ptr all = x->isAll();
  if (all)
  {
    print0(ucase ? "FORALL " : "forall ");
  }
  else
  {
    print0(ucase ? "FOR " : "for ");
  }
  x->getIndex()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " IN " : " in ");

  SQLExpr_ptr range = x->getRange();
  range->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (!all)
  {
    println();
    print0(ucase ? "LOOP" : "loop");
  }
  this->indentCount++;
  println();

  auto it_getStatements = x->getStatements()->begin();
  for (int i = 0, size = x->getStatements()->size(); i < size; ++i)
  {
    std::advance(it_getStatements, i);
    SQLStatement_ptr stmt = *it_getStatements;
    stmt->accept(std::make_shared<OracleOutputVisitor>(*this));
    if (!all)
    {
      if (i != size - 1)
      {
        println();
      }
    }
  }

  this->indentCount--;
  if (!all)
  {
    println();
    print0(ucase ? "END LOOP" : "end loop");
    SQLName_ptr endLabel = x->getEndLabel();
    if (endLabel != nullptr)
    {
      print(' ');
      endLabel->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }
  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLIfStatement_Else_ptr x)
{
  print0(ucase ? "ELSE" : "else");
  this->indentCount++;
  println();

  auto it_getStatements = x->getStatements()->begin();
  for (int i = 0, size = x->getStatements()->size(); i < size; ++i)
  {
    if (i != 0)
    {
      println();
    }
    std::advance(it_getStatements, i);
    SQLStatement_ptr item = *it_getStatements;
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  this->indentCount--;
  return false;
}

// @Override
bool OracleOutputVisitor::visit(SQLIfStatement_ElseIf_ptr x)
{
  print0(ucase ? "ELSE IF " : "else if ");
  x->getCondition()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " THEN" : " then");
  this->indentCount++;

  auto it_getStatements = x->getStatements()->begin();
  for (int i = 0, size = x->getStatements()->size(); i < size; ++i)
  {
    println();
    std::advance(it_getStatements, i);
    SQLStatement_ptr item = *it_getStatements;
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  this->indentCount--;
  return false;
}

// @Override
bool OracleOutputVisitor::visit(SQLIfStatement_ptr x)
{
  print0(ucase ? "IF " : "if ");
  int lines = this->lines;
  this->indentCount++;
  x->getCondition()->accept(std::make_shared<OracleOutputVisitor>(*this));
  this->indentCount--;

  if (lines != this->lines)
  {
    println();
  }
  else
  {
    print(' ');
  }
  print0(ucase ? "THEN" : "then");

  this->indentCount++;
  auto it_getStatements = x->getStatements()->begin();
  for (int i = 0, size = x->getStatements()->size(); i < size; ++i)
  {
    println();
    std::advance(it_getStatements, i);
    SQLStatement_ptr item = *it_getStatements;
    item->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  this->indentCount--;

  for (SQLIfStatement_ElseIf_ptr elseIf : *(x->getElseIfList()))
  {
    println();
    elseIf->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getElseItem() != nullptr)
  {
    println();
    x->getElseItem()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  println();
  print0(ucase ? "END IF" : "end if");
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleRangeExpr_ptr x)
{
  x->getLowBound()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0("..");
  x->getUpBound()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

void OracleOutputVisitor::visitColumnDefault(SQLColumnDefinition_ptr x)
{
  if (instanceof <SQLObject, SQLBlockStatement>(x->getParent()))
  {
    print0(" := ");
  }
  else
  {
    print0(ucase ? " DEFAULT " : " default ");
  }
  printExpr(x->getDefaultExpr(), BOOL::FALSE);
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OraclePrimaryKey_ptr x)
{
  if (x->SQLUnique::getName() != nullptr)
  {
    print0(ucase ? "CONSTRAINT " : "constraint ");
    x->SQLUnique::getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(' ');
  }
  print0(ucase ? "PRIMARY KEY (" : "primary key (");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLSelectOrderByItem, SQLObject>(x->getColumns());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');

  BOOL_ptr rely = x->getRely();
  if (rely != BOOL::NIL)
  {
    if (rely)
    {
      print0(ucase ? " RELY" : " rely");
    }
  }

  printConstraintState(x);

  BOOL_ptr validate = x->SQLConstraintImpl::getValidate();
  if (validate != BOOL::NIL)
  {
    if (validate)
    {
      print0(ucase ? " VALIDATE" : " validate");
    }
    else
    {
      print0(ucase ? " NOVALIDATE" : " novalidate");
    }
  }

  return BOOL::FALSE;
}

void OracleOutputVisitor::printConstraintState(OracleConstraint_ptr x)
{
  this->indentCount++;
  if (x->getUsing() != nullptr)
  {
    println();
    x->getUsing()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getExceptionsInto() != nullptr)
  {
    println();
    print0(ucase ? "EXCEPTIONS INTO " : "exceptions into ");
    x->getExceptionsInto()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  BOOL_ptr enable = x->getEnable();
  if (enable != BOOL::NIL)
  {
    if (enable)
    {
      print0(ucase ? " ENABLE" : " enable");
    }
    else
    {
      print0(ucase ? " DISABLE" : " disable");
    }
  }

  if (x->getInitially() != nullptr)
  {
    print0(ucase ? " INITIALLY " : " initially ");
    print0(x->getInitially()->name);
  }

  if (x->getDeferrable() != BOOL::NIL)
  {
    if (x->getDeferrable())
    {
      print0(ucase ? " DEFERRABLE" : " deferrable");
    }
    else
    {
      print0(ucase ? " NOT DEFERRABLE" : " not deferrable");
    }
  }
  this->indentCount--;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCreateTableStatement_ptr x)
{
  printCreateTable(x, BOOL::FALSE);

  if (x->getOf() != nullptr)
  {
    println();
    print0(ucase ? "OF " : "of ");
    x->getOf()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  OracleCreateTableStatement_OIDIndex_ptr oidIndex = x->getOidIndex();
  if (oidIndex != nullptr)
  {
    println();
    oidIndex->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  OracleCreateTableStatement_Organization_ptr organization = x->getOrganization();
  if (organization != nullptr)
  {
    println();
    this->indentCount++;
    organization->accept(std::make_shared<OracleOutputVisitor>(*this));
    this->indentCount--;
  }

  if (x->getIncluding()->size() > 0)
  {
    print0(ucase ? " INCLUDING " : " including ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(x->getIncluding());
    printAndAccept(tmp1, make_string_ptr(", "));
    print0(ucase ? " OVERFLOW " : " overflow ");
  }

  printOracleSegmentAttributes(x);

  if (x->isInMemoryMetadata())
  {
    println();
    print0(ucase ? "IN_MEMORY_METADATA" : "in_memory_metadata");
  }

  if (x->isCursorSpecificSegment())
  {
    println();
    print0(ucase ? "CURSOR_SPECIFIC_SEGMENT" : "cursor_specific_segment");
  }

  if (x->getParallel() == BOOL::TRUE)
  {
    println();
    print0(ucase ? "PARALLEL" : "parallel");

    SQLExpr_ptr parallelValue = x->getParallelValue();
    if (parallelValue != nullptr)
    {
      print(' ');
      printExpr(parallelValue);
    }
  }
  else if (x->getParallel() == BOOL::FALSE)
  {
    println();
    print0(ucase ? "NOPARALLEL" : "noparallel");
  }

  if (x->getCache() == BOOL::TRUE)
  {
    println();
    print0(ucase ? "CACHE" : "cache");
  }
  else if (x->getCache() == BOOL::FALSE)
  {
    println();
    print0(ucase ? "NOCACHE" : "nocache");
  }

  if (x->getLobStorage() != nullptr)
  {
    println();
    x->getLobStorage()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->isOnCommitPreserveRows())
  {
    println();
    print0(ucase ? "ON COMMIT PRESERVE ROWS" : "on commit preserve rows");
  }
  else if (x->isOnCommitDeleteRows())
  {
    println();
    print0(ucase ? "ON COMMIT DELETE ROWS" : "on commit delete rows");
  }

  if (x->isMonitoring())
  {
    println();
    print0(ucase ? "MONITORING" : "monitoring");
  }

  if (x->getPartitioning() != nullptr)
  {
    println();
    print0(ucase ? "PARTITION BY " : "partition by ");
    x->getPartitioning()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getCluster() != nullptr)
  {
    println();
    print0(ucase ? "CLUSTER " : "cluster ");
    x->getCluster()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print0(" (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(x->getClusterColumns());
    printAndAccept(tmp1, make_string_ptr(","));
    print0(")");
  }

  OracleXmlColumnProperties_ptr xmlTypeColumnProperties = x->getXmlTypeColumnProperties();
  if (xmlTypeColumnProperties != nullptr)
  {
    println();
    xmlTypeColumnProperties->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLSelect_ptr select = x->getSelect();
  if (select != nullptr)
  {
    println();
    print0(ucase ? "AS" : "as");
    println();
    select->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleStorageClause_ptr x)
{
  print0(ucase ? "STORAGE (" : "storage (");

  this->indentCount++;
  SQLExpr_ptr initial = x->getInitial();
  if (initial != nullptr)
  {
    println();
    print0(ucase ? "INITIAL " : "initial ");
    printExpr(initial, BOOL::FALSE);
  }

  SQLExpr_ptr next = x->getNext();
  if (next != nullptr)
  {
    println();
    print0(ucase ? "NEXT " : "next ");
    printExpr(next, BOOL::FALSE);
  }

  SQLExpr_ptr minExtents = x->getMinExtents();
  if (minExtents != nullptr)
  {
    println();
    print0(ucase ? "MINEXTENTS " : "minextents ");
    printExpr(minExtents, BOOL::FALSE);
  }

  SQLExpr_ptr maxExtents = x->getMaxExtents();
  if (maxExtents != nullptr)
  {
    println();
    print0(ucase ? "MAXEXTENTS " : "maxextents ");
    printExpr(maxExtents, BOOL::FALSE);
  }

  SQLExpr_ptr pctIncrease = x->getPctIncrease();
  if (pctIncrease != nullptr)
  {
    println();
    print0(ucase ? "PCTINCREASE " : "pctincrease ");
    printExpr(pctIncrease, BOOL::FALSE);
  }

  SQLExpr_ptr maxSize = x->getMaxSize();
  if (maxSize != nullptr)
  {
    println();
    print0(ucase ? "MAXSIZE " : "maxsize ");
    printExpr(maxSize, BOOL::FALSE);
  }

  SQLExpr_ptr freeLists = x->getFreeLists();
  if (freeLists != nullptr)
  {
    println();
    print0(ucase ? "FREELISTS " : "freelists ");
    printExpr(freeLists, BOOL::FALSE);
  }

  SQLExpr_ptr freeListGroups = x->getFreeListGroups();
  if (freeListGroups != nullptr)
  {
    println();
    print0(ucase ? "FREELIST GROUPS " : "freelist groups ");
    printExpr(freeListGroups, BOOL::FALSE);
  }

  SQLExpr_ptr bufferPool = x->getBufferPool();
  if (bufferPool != nullptr)
  {
    println();
    print0(ucase ? "BUFFER_POOL " : "buffer_pool ");
    printExpr(bufferPool, BOOL::FALSE);
  }

  SQLExpr_ptr objno = x->getObjno();
  if (objno != nullptr)
  {
    println();
    print0(ucase ? "OBJNO " : "objno ");
    printExpr(objno, BOOL::FALSE);
  }

  if (x->getFlashCache() != nullptr)
  {
    println();
    print0(ucase ? "FLASH_CACHE " : "flash_cache ");
    print0(ucase ? x->getFlashCache()->name : StringUtils::toLower(x->getFlashCache()->name));
  }

  if (x->getCellFlashCache() != nullptr)
  {
    println();
    print0(ucase ? "CELL_FLASH_CACHE " : "cell_flash_cache ");
    print0(ucase ? x->getCellFlashCache()->name : StringUtils::toLower(x->getCellFlashCache()->name));
  }
  this->indentCount--;
  println();
  print(')');

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleGotoStatement_ptr x)
{
  print0(ucase ? "GOTO " : "GOTO ");
  x->getLabel()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleLabelStatement_ptr x)
{
  print0("<<");
  x->getLabel()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(">>");
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTriggerStatement_ptr x)
{
  print0(ucase ? "ALTER TRIGGER " : "alter trigger ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->isCompile())
  {
    print0(ucase ? " COMPILE" : " compile");
  }

  if (x->getEnable() != BOOL::NIL)
  {
    if (x->getEnable() == BOOL::TRUE)
    {
      print0(ucase ? "ENABLE" : "enable");
    }
    else
    {
      print0(ucase ? "DISABLE" : "disable");
    }
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterSynonymStatement_ptr x)
{
  print0(ucase ? "ALTER SYNONYM " : "alter synonym ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->isCompile())
  {
    print0(ucase ? " COMPILE" : " compile");
  }

  if (x->getEnable() != BOOL::NIL)
  {
    if (x->getEnable() == BOOL::TRUE)
    {
      print0(ucase ? "ENABLE" : "enable");
    }
    else
    {
      print0(ucase ? "DISABLE" : "disable");
    }
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterViewStatement_ptr x)
{
  print0(ucase ? "ALTER VIEW " : "alter view ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->isCompile())
  {
    print0(ucase ? " COMPILE" : " compile");
  }

  if (x->getEnable() != BOOL::NIL)
  {
    if (x->getEnable() == BOOL::TRUE)
    {
      print0(ucase ? "ENABLE" : "enable");
    }
    else
    {
      print0(ucase ? "DISABLE" : "disable");
    }
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableMoveTablespace_ptr x)
{
  print0(ucase ? " MOVE TABLESPACE " : " move tablespace ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableRowMovement_ptr x)
{
  if (x->isEnable() == BOOL::TRUE)
  {
    print0(ucase ? " ENABLE ROW MOVEMENT " : " enable row movement ");
  }
  else
  {
    print0(ucase ? " DISABLE ROW MOVEMENT " : " disable row movement ");
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTableShrinkSpace_ptr x)
{
  print0(ucase ? " SHRINK SPACE " : " shrink space ");

  if (x->isCompact())
  {
    print0(ucase ? "COMPACT " : "compact ");
  }

  if (x->isCascade())
  {
    print0(ucase ? "CASCADE " : "cascade ");
  }

  if (x->isCheck())
  {
    print0(ucase ? "CHECK " : "check ");
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterSummaryStatement_ptr x)
{
  print0(ucase ? "ALTER SUMMARY " : "alter summary ");

  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->isCompile())
  {
    print0(ucase ? " COMPILE " : " compile ");
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleFileSpecification_ptr x)
{
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getFileNames());
  printAndAccept(tmp1, make_string_ptr(", "));

  if (x->getSize() != nullptr)
  {
    print0(ucase ? " SIZE " : " size ");
    x->getSize()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->isAutoExtendOff())
  {
    print0(ucase ? " AUTOEXTEND OFF" : " autoextend off");
  }
  else if (x->getAutoExtendOn() != nullptr)
  {
    print0(ucase ? " AUTOEXTEND ON " : " autoextend on ");
    x->getAutoExtendOn()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTablespaceAddDataFile_ptr x)
{
  print0(ucase ? "ADD DATAFILE" : "add datafile");
  this->indentCount++;
  for (OracleFileSpecification_ptr file : *x->getFiles())
  {
    println();
    file->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  this->indentCount--;
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleAlterTablespaceStatement_ptr x)
{
  print0(ucase ? "ALTER TABLESPACE " : "alter tablespace ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  println();
  x->getItem()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLTruncateStatement_ptr x)
{
  print0(ucase ? "TRUNCATE TABLE " : "truncate table ");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExprTableSource, SQLObject>(x->getTableSources());
  printAndAccept(tmp1, make_string_ptr(", "));

  if (x->isPurgeSnapshotLog())
  {
    print0(ucase ? " PURGE SNAPSHOT LOG" : " purge snapshot log");
  }
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleExitStatement_ptr x)
{
  print0(ucase ? "EXIT" : "exit");

  if (x->getLabel() != nullptr)
  {
    print(' ');
    print0(x->getLabel());
  }

  if (x->getWhen() != nullptr)
  {
    print0(ucase ? " WHEN " : " when ");
    x->getWhen()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleContinueStatement_ptr x)
{
  print0(ucase ? "CONTINUE" : "continue");

  string_ptr label = x->getLabel();
  if (label != nullptr)
  {
    print(' ');
    print0(label);
  }

  if (x->getWhen() != nullptr)
  {
    print0(ucase ? " WHEN " : " when ");
    x->getWhen()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleRaiseStatement_ptr x)
{
  print0(ucase ? "RAISE" : "raise");
  if (x->getException() != nullptr)
  {
    print(' ');
    x->getException()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  print(';');
  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLSavePointStatement_ptr x)
{
  print0(ucase ? "SAVEPOINT" : "savepoint");
  if (x->getName() != nullptr)
  {
    print0(ucase ? " TO " : " to ");
    x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return false;
}

// @Override
bool OracleOutputVisitor::visit(SQLCreateFunctionStatement_ptr x)
{
  BOOL_ptr create = x->isCreate();
  if (!create)
  {
    print0(ucase ? "FUNCTION " : "function ");
  }
  else if (x->isOrReplace())
  {
    print0(ucase ? "CREATE OR REPLACE FUNCTION " : "create or replace function ");
  }
  else
  {
    print0(ucase ? "CREATE FUNCTION " : "create function ");
  }
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  int paramSize = x->getParameters()->size();

  if (paramSize > 0)
  {
    print0(" (");
    this->indentCount++;
    println();

    auto it_getParameters = x->getParameters()->begin();
    for (int i = 0; i < paramSize; ++i)
    {
      if (i != 0)
      {
        print0(", ");
        println();
      }
      std::advance(it_getParameters, i);
      SQLParameter_ptr param = *it_getParameters;
      param->accept(std::make_shared<OracleOutputVisitor>(*this));
    }

    this->indentCount--;
    println();
    print(')');
  }

  string_ptr wrappedSource = x->getWrappedSource();
  if (wrappedSource != nullptr)
  {
    print0(ucase ? " WRAPPED " : " wrapped ");
    print0(wrappedSource);

    if (x->isAfterSemi())
    {
      print(';');
    }
    return false;
  }

  println();
  print(ucase ? "RETURN " : "return ");
  x->getReturnDataType()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->isPipelined())
  {
    print(ucase ? "PIPELINED " : "pipelined ");
  }

  if (x->isDeterministic())
  {
    print(ucase ? "DETERMINISTIC " : "deterministic ");
  }

  SQLName_ptr authid = x->getAuthid();
  if (authid != nullptr)
  {
    print(ucase ? " AUTHID " : " authid ");
    authid->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLStatement_ptr block = x->getBlock();

  if (block != nullptr && !create)
  {
    println();
    println(make_string_ptr("IS"));
  }
  else
  {
    println();
    if (instanceof <SQLStatement, SQLBlockStatement>(block))
    {
      SQLBlockStatement_ptr blockStatement = std::dynamic_pointer_cast<SQLBlockStatement>(block);
      if (blockStatement->getParameters()->size() > 0 ||
          authid != nullptr)
      {
        println(ucase ? "AS" : "as");
      }
    }
  }

  string_ptr javaCallSpec = x->getJavaCallSpec();
  if (javaCallSpec != nullptr)
  {
    print0(ucase ? "LANGUAGE JAVA NAME '" : "language java name '");
    print0(javaCallSpec);
    print('\'');
    return false;
  }

  if (x->isParallelEnable())
  {
    print0(ucase ? "PARALLEL_ENABLE" : "parallel_enable");
    println();
  }

  if (x->isAggregate())
  {
    print0(ucase ? "AGGREGATE" : "aggregate");
    println();
  }

  SQLName_ptr using_ = x->getUsing();
  if (using_ != nullptr)
  {
    print0(ucase ? "USING " : "using ");
    using_->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (block != nullptr)
  {
    block->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCreateDatabaseDbLinkStatement_ptr x)
{
  print0(ucase ? "CREATE " : "create ");
  if (x->isShared())
  {
    print0(ucase ? "SHARE " : "share ");
  }

  if (x->isPublic())
  {
    print0(ucase ? "PUBLIC " : "");
  }

  print0(ucase ? "DATABASE LINK " : "database link ");

  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->getUser() != nullptr)
  {
    print0(ucase ? " CONNECT TO " : " connect to ");
    x->getUser()->accept(std::make_shared<OracleOutputVisitor>(*this));

    if (x->getPassword() != nullptr)
    {
      print0(ucase ? " IDENTIFIED BY " : " identified by ");
      print0(x->getPassword());
    }
  }

  if (x->getAuthenticatedUser() != nullptr)
  {
    print0(ucase ? " AUTHENTICATED BY " : " authenticated by ");
    x->getAuthenticatedUser()->accept(std::make_shared<OracleOutputVisitor>(*this));
    if (x->getAuthenticatedPassword() != nullptr)
    {
      print0(ucase ? " IDENTIFIED BY " : " identified by ");
      print0(x->getAuthenticatedPassword());
    }
  }

  if (x->getUsing() != nullptr)
  {
    print0(ucase ? " USING " : " using ");
    x->getUsing()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleDropDbLinkStatement_ptr x)
{
  print0(ucase ? "DROP " : "drop ");
  if (x->isPublic())
  {
    print0(ucase ? "PUBLIC " : "");
  }
  print0(ucase ? "DATABASE LINK " : "database link ");
  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

bool OracleOutputVisitor::visit(SQLCharacterDataType_ptr x)
{
  print0(x->getName());
  SQLExpr_list_ptr arguments = x->getArguments();
  if (arguments->size() > 0)
  {
    print('(');
    SQLExpr_ptr arg0 = *(arguments->begin());
    printExpr(arg0, BOOL::FALSE);
    if (x->getCharType() != nullptr)
    {
      print(' ');
      print0(x->getCharType());
    }
    print(')');
  }
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleDataTypeIntervalYear_ptr x)
{
  print0(x->getName());
  if (x->getArguments()->size() > 0)
  {
    print('(');
    (*(x->getArguments()->begin()))->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');
  }

  print0(ucase ? " TO MONTH" : " to month");

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleDataTypeIntervalDay_ptr x)
{
  print0(x->getName());
  if (x->getArguments()->size() > 0)
  {
    print('(');
    (*(x->getArguments()->begin()))->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');
  }

  print0(ucase ? " TO SECOND" : " to second");

  if (x->getFractionalSeconds()->size() > 0)
  {
    print('(');
    (*(x->getFractionalSeconds()->begin()))->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(')');
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleUsingIndexClause_ptr x)
{
  print0(ucase ? "USING INDEX" : "using index");
  SQLObject_ptr index = x->getIndex();
  if (index != nullptr)
  {
    print(' ');
    if (instanceof <SQLObject, SQLCreateIndexStatement>(index))
    {
      print('(');
      index->accept(std::make_shared<OracleOutputVisitor>(*this));
      print(')');
    }
    else
    {
      index->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  printOracleSegmentAttributes(x);

  if (x->isComputeStatistics())
  {
    println();
    print0(ucase ? "COMPUTE STATISTICS" : "compute statistics");
  }

  if (x->getEnable() != BOOL::NIL)
  {
    if (x->getEnable() == BOOL::TRUE)
    {
      println();
      print0(ucase ? "ENABLE" : "enable");
    }
    else
    {
      println();
      print0(ucase ? "DISABLE" : "disable");
    }
  }

  if (x->isReverse())
  {
    println();
    print0(ucase ? "REVERSE" : "reverse");
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleLobStorageClause_ptr x)
{
  print0(ucase ? "LOB (" : "lob (");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(x->getItems());
  printAndAccept(tmp1, make_string_ptr(","));
  print0(ucase ? ") STORE AS" : ") store as");

  if (x->isSecureFile())
  {
    print0(ucase ? " SECUREFILE" : " securefile");
  }

  if (x->isBasicFile())
  {
    print0(ucase ? " BASICFILE" : " basicfile");
  }

  SQLName_ptr segementName = x->getSegementName();
  if (segementName != nullptr)
  {
    print(' ');
    segementName->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  print0(" (");
  this->indentCount++;
  printOracleSegmentAttributes(x);

  if (x->getEnable() != BOOL::NIL)
  {
    println();
    if (x->getEnable() == BOOL::TRUE)
    {
      print0(ucase ? "ENABLE STORAGE IN ROW" : "enable storage in row");
    }
    else
    {
      print0(ucase ? "DISABLE STORAGE IN ROW" : "disable storage in row");
    }
  }

  if (x->getChunk() != nullptr)
  {
    println();
    print0(ucase ? "CHUNK " : "chunk ");
    x->getChunk()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->getCache() != BOOL::NIL)
  {
    println();
    if (x->getCache() == BOOL::TRUE)
    {
      print0(ucase ? "CACHE" : "cache");
    }
    else
    {
      print0(ucase ? "NOCACHE" : "nocache");
    }
  }

  if (x->getKeepDuplicate() != BOOL::NIL)
  {
    println();
    if (x->getKeepDuplicate() == BOOL::TRUE)
    {
      print0(ucase ? "KEEP_DUPLICATES" : "keep_duplicates");
    }
    else
    {
      print0(ucase ? "DEDUPLICATE" : "deduplicate");
    }
  }

  if (x->isRetention())
  {
    println();
    print0(ucase ? "RETENTION" : "retention");
  }

  this->indentCount--;
  println();
  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleUnique_ptr x)
{
  SQLASTOutputVisitor::visit(std::dynamic_pointer_cast<SQLUnique>(x));

  printConstraintState(x);
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleForeignKey_ptr x)
{
  SQLASTOutputVisitor::visit(std::dynamic_pointer_cast<SQLForeignKeyImpl>(x));

  printConstraintState(x);
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCheck_ptr x)
{
  SQLASTOutputVisitor::visit(std::dynamic_pointer_cast<SQLCheck>(x));

  printConstraintState(x);
  return BOOL::FALSE;
}

// @Override
void OracleOutputVisitor::printCascade()
{
  print0(ucase ? " CASCADE CONSTRAINTS" : " cascade constraints");
}

BOOL_ptr OracleOutputVisitor::visit(SQLCharExpr_ptr x, BOOL_ptr parameterized)
{
  if (x->getText() != nullptr && x->getText()->length() == 0)
  {
    print0(ucase ? "NULL" : "nullptr");
  }
  else
  {
    SQLASTOutputVisitor::visit(x, parameterized);
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleSupplementalIdKey_ptr x)
{
  print0(ucase ? "SUPPLEMENTAL LOG DATA (" : "supplemental log data (");

  int count = 0;

  if (x->isAll())
  {
    print0(ucase ? "ALL" : "all");
    count++;
  }

  if (x->isPrimaryKey())
  {
    if (count != 0)
    {
      print0(", ");
    }
    print0(ucase ? "PRIMARY KEY" : "primary key");
    count++;
  }

  if (x->isUnique())
  {
    if (count != 0)
    {
      print0(", ");
    }
    print0(ucase ? "UNIQUE" : "unique");
    count++;
  }

  if (x->isUniqueIndex())
  {
    if (count != 0)
    {
      print0(", ");
    }
    print0(ucase ? "UNIQUE INDEX" : "unique index");
    count++;
  }

  if (x->isForeignKey())
  {
    if (count != 0)
    {
      print0(", ");
    }
    print0(ucase ? "FOREIGN KEY" : "foreign key");
    count++;
  }

  print0(ucase ? ") COLUMNS" : ") columns");
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleSupplementalLogGrp_ptr x)
{
  print0(ucase ? "SUPPLEMENTAL LOG GROUP " : "supplemental log group ");
  x->getGroup()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(" (");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(x->getColumns());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');
  if (x->isAlways())
  {
    print0(ucase ? " ALWAYS" : " always");
  }
  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleCreateTableStatement_Organization_ptr x)
{
  string_ptr type = x->getType();

  print0(ucase ? "ORGANIZATION " : "organization ");
  print0(ucase ? type : StringUtils::toLower(type));

  printOracleSegmentAttributes(x);

  // if (x->getPctthreshold() != nullptr)
  // {
  println();
  print0(ucase ? "PCTTHRESHOLD " : "pctthreshold ");
  print(x->getPctthreshold());
  // }

  if (StringUtils::equalsIgnoreCase(make_string_ptr("EXTERNAL"), type))
  {
    print0(" (");

    this->indentCount++;
    if (x->getExternalType() != nullptr)
    {
      println();
      print0(ucase ? "TYPE " : "type ");
      x->getExternalType()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }

    if (x->getExternalDirectory() != nullptr)
    {
      println();
      print0(ucase ? "DEFAULT DIRECTORY " : "default directory ");
      x->getExternalDirectory()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }

    if (x->getExternalDirectoryRecordFormat() != nullptr)
    {
      println();
      this->indentCount++;
      print0(ucase ? "ACCESS PARAMETERS (" : "access parameters (");
      x->getExternalDirectoryRecordFormat()->accept(std::make_shared<OracleOutputVisitor>(*this));
      this->indentCount--;
      println();
      print(')');
    }

    if (x->getExternalDirectoryLocation()->size() > 0)
    {
      println();
      print0(ucase ? "LOCATION (" : " location(");
      SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getExternalDirectoryLocation());
      printAndAccept(tmp1, make_string_ptr(", "));
      print(')');
    }

    this->indentCount--;
    println();
    print(')');

    if (x->getExternalRejectLimit() != nullptr)
    {
      println();
      print0(ucase ? "REJECT LIMIT " : "reject limit ");
      x->getExternalRejectLimit()->accept(std::make_shared<OracleOutputVisitor>(*this));
    }
  }

  return BOOL::FALSE;
}

BOOL_ptr OracleOutputVisitor::visit(OracleCreateTableStatement_OIDIndex_ptr x)
{
  print0(ucase ? "OIDINDEX" : "oidindex");

  if (x->getName() != nullptr)
  {
    print(' ');
    x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  print(" (");
  this->indentCount++;
  printOracleSegmentAttributes(x);
  this->indentCount--;
  println();
  print(")");
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCreatePackageStatement_ptr x)
{
  if (x->isOrReplace())
  {
    print0(ucase ? "CREATE OR REPLACE PACKAGE " : "create or replace procedure ");
  }
  else
  {
    print0(ucase ? "CREATE PACKAGE " : "create procedure ");
  }

  if (x->isBody())
  {
    print0(ucase ? "BODY " : "body ");
  }

  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  if (x->isBody())
  {
    println();
    print0(ucase ? "BEGIN" : "begin");
  }

  this->indentCount++;

  SQLStatement_list_ptr statements = x->getStatements();
  auto it_statements = statements->begin();
  for (int i = 0, size = statements->size(); i < size; ++i)
  {
    println();
    std::advance(it_statements, i);
    SQLStatement_ptr stmt = *it_statements;
    stmt->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  this->indentCount--;

  if (x->isBody() || statements->size() > 0)
  {
    println();
    print0(ucase ? "END " : "end ");
    x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print(';');
  }

  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLAssignItem_ptr x)
{
  x->getTarget()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(" := ");
  x->getValue()->accept(std::make_shared<OracleOutputVisitor>(*this));
  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleExecuteImmediateStatement_ptr x)
{
  print0(ucase ? "EXECUTE IMMEDIATE " : "execute immediate ");
  x->getDynamicSql()->accept(std::make_shared<OracleOutputVisitor>(*this));

  SQLExpr_list_ptr into = x->getInto();
  if (into->size() > 0)
  {
    print0(ucase ? " INTO " : " into ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(into);
    printAndAccept(tmp1, make_string_ptr(", "));
  }

  SQLArgument_list_ptr using_ = x->getArguments();
  if (using_->size() > 0)
  {
    print0(ucase ? " USING " : " using ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLArgument, SQLObject>(using_);
    printAndAccept(tmp1, make_string_ptr(", "));
  }

  SQLExpr_list_ptr returnInto = x->getReturnInto();
  if (returnInto->size() > 0)
  {
    print0(ucase ? " RETURNNING INTO " : " returnning into ");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(returnInto);
    printAndAccept(tmp1, make_string_ptr(", "));
  }
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleTreatExpr_ptr x)
{
  print0(ucase ? "TREAT (" : "treat (");
  x->getExpr()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print0(ucase ? " AS " : " as ");
  if (x->isRef())
  {
    print0(ucase ? "REF " : "ref ");
  }
  x->getType()->accept(std::make_shared<OracleOutputVisitor>(*this));
  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCreateSynonymStatement_ptr x)
{
  if (x->isOrReplace())
  {
    print0(ucase ? "CREATE OR REPLACE " : "create or replace ");
  }
  else
  {
    print0(ucase ? "CREATE " : "create ");
  }

  if (x->isPublic())
  {
    print0(ucase ? "PUBLIC " : "");
  }

  print0(ucase ? "SYNONYM " : "synonym ");

  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  print0(ucase ? " FOR " : " for ");
  x->getObject()->accept(std::make_shared<OracleOutputVisitor>(*this));

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleCreateTypeStatement_ptr x)
{
  if (x->isOrReplace())
  {
    print0(ucase ? "CREATE OR REPLACE TYPE " : "create or replace type ");
  }
  else
  {
    print0(ucase ? "CREATE TYPE " : "create type ");
  }

  if (x->isBody())
  {
    print0(ucase ? "BODY " : "body ");
  }

  x->getName()->accept(std::make_shared<OracleOutputVisitor>(*this));

  SQLName_ptr under = x->getUnder();
  if (under != nullptr)
  {
    print0(ucase ? " UNDER " : " under ");
    under->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  SQLName_ptr authId = x->getAuthId();
  if (authId != nullptr)
  {
    print0(ucase ? " AUTHID " : " authid ");
    authId->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  if (x->isForce())
  {
    print0(ucase ? "FORCE " : "force ");
  }

  SQLParameter_list_ptr parameters = x->getParameters();
  SQLDataType_ptr tableOf = x->getTableOf();

  if (x->isObject())
  {
    print0(" AS OBJECT");
  }

  if (parameters->size() > 0)
  {
    if (x->isParen())
    {
      print(" (");
    }
    else
    {
      print0(ucase ? " IS" : " is");
    }
    indentCount++;
    println();

    auto it_parameters = parameters->begin();
    for (int i = 0; i < parameters->size(); ++i)
    {
      std::advance(it_parameters, i);
      SQLParameter_ptr param = *it_parameters;
      param->accept(std::make_shared<OracleOutputVisitor>(*this));

      SQLDataType_ptr dataType = param->getDataType();

      if (i < parameters->size() - 1)
      {
        if (instanceof <SQLDataType, OracleFunctionDataType>(dataType) &&
                           (std::dynamic_pointer_cast<OracleFunctionDataType>(dataType))->getBlock() != nullptr)
        {
          // skip
          println();
        }
        else if (instanceof <SQLDataType, OracleProcedureDataType>(dataType) &&
                                (std::dynamic_pointer_cast<OracleProcedureDataType>(dataType))->getBlock() != nullptr)
        {
          // skip
          println();
        }
        else
        {
          println(", ");
        }
      }
    }

    indentCount--;
    println();

    if (x->isParen())
    {
      print0(")");
    }
    else
    {
      print0("END");
    }
  }
  else if (tableOf != nullptr)
  {
    print0(ucase ? " AS TABLE OF " : " as table of ");
    tableOf->accept(std::make_shared<OracleOutputVisitor>(*this));
  }
  else if (x->getVarraySizeLimit() != nullptr)
  {
    print0(ucase ? " VARRAY (" : " varray (");
    x->getVarraySizeLimit()->accept(std::make_shared<OracleOutputVisitor>(*this));
    print0(ucase ? ") OF " : ") of ");
    x->getVarrayDataType()->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  BOOL_ptr isFinal = x->getFinal();
  if (isFinal != BOOL::NIL)
  {
    if (isFinal == BOOL::TRUE)
    {
      print0(ucase ? " FINAL" : " final");
    }
    else
    {
      print0(ucase ? " NOT FINAL" : " not final");
    }
  }

  BOOL_ptr instantiable = x->getInstantiable();
  if (instantiable != BOOL::NIL)
  {
    if (instantiable == BOOL::TRUE)
    {
      print0(ucase ? " INSTANTIABLE" : " instantiable");
    }
    else
    {
      print0(ucase ? " NOT INSTANTIABLE" : " not instantiable");
    }
  }

  string_ptr wrappedSource = x->getWrappedSource();
  if (wrappedSource != nullptr)
  {
    print0(ucase ? " WRAPPED" : " wrapped");
    print0(wrappedSource);
  }

  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OraclePipeRowStatement_ptr x)
{
  print0(ucase ? "PIPE ROW(" : "pipe row(");
  SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(x->getParameters());
  printAndAccept(tmp1, make_string_ptr(", "));
  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleIsOfTypeExpr_ptr x)
{
  printExpr(x->getExpr());
  print0(ucase ? " IS OF TYPE (" : " is of type (");

  SQLExpr_list_ptr types = x->getTypes();
  auto it_types = types->begin();
  for (int i = 0, size = types->size(); i < size; ++i)
  {
    if (i != 0)
    {
      print0(", ");
    }
    std::advance(it_types, i);
    SQLExpr_ptr type = *it_types;

    if (true == (type->getAttribute("ONLY")->getBool()))
    {
      print0(ucase ? "ONLY " : "only ");
    }
    type->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  print(')');
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleRunStatement_ptr x)
{
  print0("@@");
  printExpr(x->getExpr());
  return BOOL::FALSE;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleXmlColumnProperties_ptr x)
{
  print0(ucase ? "XMLTYPE " : "xmltype ");
  x->getColumn()->accept(std::make_shared<OracleOutputVisitor>(*this));

  OracleXmlColumnProperties_OracleXMLTypeStorage_ptr storage = x->getStorage();
  if (storage != nullptr)
  {
    storage->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  BOOL_ptr allowNonSchema = x->getAllowNonSchema();
  if (allowNonSchema != BOOL::NIL)
  {
    if (allowNonSchema == BOOL::TRUE)
    {
      print0(ucase ? " ALLOW NONSCHEMA" : " allow nonschema");
    }
    else
    {
      print0(ucase ? " DISALLOW NONSCHEMA" : " disallow nonschema");
    }
  }

  BOOL_ptr allowAnySchema = x->getAllowAnySchema();
  if (allowAnySchema != BOOL::NIL)
  {
    if (allowAnySchema == BOOL::TRUE)
    {
      print0(ucase ? " ALLOW ANYSCHEMA" : " allow anyschema");
    }
    else
    {
      print0(ucase ? " DISALLOW ANYSCHEMA" : " disallow anyschema");
    }
  }

  return BOOL::FALSE;
}

// @Override
bool OracleOutputVisitor::visit(SQLExprTableSource_ptr x)
{
  printTableSourceExpr(x->getExpr());

  SQLTableSampling_ptr sampling = x->getSampling();
  if (sampling != nullptr)
  {
    print(' ');
    sampling->accept(std::make_shared<OracleOutputVisitor>(*this));
  }

  string_ptr alias = x->getAlias();
  SQLName_list_ptr columns = x->getColumnsDirect();
  if (alias != nullptr)
  {
    SQLObject_ptr parent = x->getParent();
    if (instanceof <SQLObject, SQLCreateIndexStatement>(parent) ||
        instanceof <SQLObject, SQLMergeStatement>(parent) ||
        instanceof <SQLObject, SQLDeleteStatement>(parent))
    {
      print(' ');
      print0(alias);
    }
    else
    {
      print(' ');
      print0(ucase ? " AS " : " as ");
      print0(alias);
    }
  }

  if (columns != nullptr && columns->size() > 0)
  {
    print(" (");
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLName, SQLObject>(columns);
    printAndAccept(tmp1, make_string_ptr(", "));
    print(')');
  }

  if (isPrettyFormat() && x->hasAfterComment())
  {
    print(' ');
    printlnComment(x->getAfterCommentsDirect());
  }

  return false;
}

// @Override
BOOL_ptr OracleOutputVisitor::visit(OracleXmlColumnProperties_OracleXMLTypeStorage_ptr x)
{
  return BOOL::FALSE;
}

bool OracleOutputVisitor::visit(SQLSubPartition_ptr x)
{
  SQLASTOutputVisitor::visit(x);
  incrementIndent();
  printOracleSegmentAttributes(x);
  decrementIndent();
  return false;
}

bool OracleOutputVisitor::visit(SQLPartitionValue_ptr x)
{
  SQLASTOutputVisitor::visit(x);
  incrementIndent();
  printOracleSegmentAttributes(x);
  decrementIndent();
  return false;
}
